#ifndef __MY_DATE__
#define __MY_DATE__
#include <unordered_map>
#include <pthread.h>
#include "util.hpp"
#include "config.hpp"

namespace cloud
{
    typedef struct BackupInfo
    {
        bool pack_flag;//是否压缩标识
        size_t fsize;//文件大小
        time_t mtime;//最后一次修改时间
        time_t atime;//最后一次访问时间
        std::string real_path;//文件实际存储路径名称
        std::string pack_path;//压缩包存储路径名称
        std::string url;//请求资源的路径
        bool NewBackupInfo(const std::string &realpath)//填充数据接口
        {
            FileUtil fu(realpath);
            if (fu.Exists() == false)
            {
                std::cout << "new backupinfo file not exists!\n";
                return false;
            }
            Config *config = Config::GetInstance();
            std::string packdir = config->GetPackDir();//获取压缩包存放目录
            std::string packsuffix = config->GetPackFileSuffix();//获取文件后缀名称
            std::string download_prefix = config->GetDownloadPrefix();//获取下载的url前缀路径

            this->pack_flag = false;
            this->fsize = fu.FileSize();
            this->mtime = fu.LastMtime();
            this->atime = fu.LastAtime();
            this->real_path = realpath;
            // ./backdir/a.txt -> ./packdir/a.txt.lz
            this->pack_path = packdir + fu.Filename() + packsuffix;
            // ./backdir/a.txt -> ./download/a.txt.lz  ./download/：这是下载的前缀
            this->url = download_prefix + fu.Filename();
            return true;
        }
    } BackupInfo;

    class DataManager //数据管理类
    {
    private:
        std::string _backup_file;//数据持久化存储文件
        pthread_rwlock_t _rwloack; //读写锁--读共享，写互斥，
        //互斥是串行化过程，一次只有一个访问，我们要多个线程同时去获取数据，写（修改数据）的时候大家就不能访问了，所以读共享，写互斥
        std::unordered_map<std::string, BackupInfo> _table;

    public:
        DataManager()
        {
            _backup_file = Config::GetInstance()->GetBackupFile();
            pthread_rwlock_init(&_rwloack, NULL); // 初始化读写锁
            InitLoad();
        }
        ~DataManager()
        {
            pthread_rwlock_destroy(&_rwloack); // 销毁读写锁
        }
        bool Insert(const BackupInfo &info)//输入型参数
        {
            pthread_rwlock_wrlock(&_rwloack);//插入就要修改，要加锁
            _table[info.url] = info;
            pthread_rwlock_unlock(&_rwloack);
            Storage(); // 插入过程，就有了保存的功能，有这个函数会生成cloud.dat备份文件
            return true;
        }
        bool Update(const BackupInfo &info)//输入型参数
        {
            pthread_rwlock_wrlock(&_rwloack);
            _table[info.url] = info;//当info.url相同时，就会覆盖之前的数据，和插入没有区别
            pthread_rwlock_unlock(&_rwloack);
            Storage(); // 修改过程，就有了保存的功能，有这个函数会生成cloud.dat备份文件
            return true;
        }
        bool GetOneByURL(const std::string &url, BackupInfo *info)//获取单个，根据url来获取
        {
            pthread_rwlock_wrlock(&_rwloack);
            // 因为url是key值，所以直接通过find进行查找
            auto it = _table.find(url);//根据key值查找
            if (it == _table.end())
            {
                pthread_rwlock_unlock(&_rwloack);
                return false;
            }
            *info = it->second;
            pthread_rwlock_unlock(&_rwloack);
            return true;
        }
        bool GetOneByRealPath(const std::string &realpath, BackupInfo *info)//根据真实路径获取文件信息
        {
            pthread_rwlock_wrlock(&_rwloack);
            auto it = _table.begin();
            for (; it != _table.end(); ++it)
            {
                if (it->second.real_path == realpath)
                {
                    *info = it->second;
                    pthread_rwlock_unlock(&_rwloack);//有可能退出的地方都要解锁
                    return true;
                }
            }
            pthread_rwlock_unlock(&_rwloack); // 退出的地方，都要解锁
            return false;
        }
        bool GetAll(std::vector<BackupInfo> *arry)//遍历所有信息
        {
            pthread_rwlock_wrlock(&_rwloack);
            auto it = _table.begin();
            for (; it != _table.end(); ++it)
            {
                arry->push_back(it->second);
            }
            pthread_rwlock_unlock(&_rwloack);
            return true;
        }

        bool Storage()//持续化存储，也就是备份
        {
            // 1、获取所以数据
            std::vector<BackupInfo> arry;
            this->GetAll(&arry);
            // 2、添加到Json::Value
            Json::Value root;
            for (int i = 0; i < arry.size(); i++)
            {
                Json::Value item;
                item["pack_flag"] = arry[i].pack_flag;
                item["fsize"] = (Json::Int64)arry[i].fsize;//只重载了基础数据类型，size_t是不会重载的
                item["atime"] = (Json::Int64)arry[i].atime;
                item["mtime"] = (Json::Int64)arry[i].mtime;
                item["real_path"] = arry[i].real_path;
                item["pack_path"] = arry[i].pack_path;
                item["url"] = arry[i].url;
                root.append(item); // 添加数组元素
            }
            // 3、对Json::Value序列化
            std::string body;
            JsonUtil::Serialize(root, &body);//把序列化之后的数据，传到body里去
            // 4、写文件
            FileUtil fu(_backup_file);
            fu.SetContent(body);
            return true;
        }

        bool InitLoad()//初始化加载功能：当程序运行起来后，从数据文件里把以前的数据读取加载出来
        {
            // 1、将数据文件中的数据读取出来
            FileUtil fu(_backup_file);
            if (fu.Exists() == false)
            {
                return true;
            }
            std::string body;
            fu.GetContent(&body);//把数据放到body里

            // 2、反序列化
            Json::Value root;
            JsonUtil::UnSerialize(body, &root);//从body中输入（读）到root中
            // 3、将反序列化得到的Json::Value中的数据添加到table中
            for (int i = 0; i < root.size(); i++)
            {
                BackupInfo info;
                info.pack_flag = root[i]["pack_flag"].asBool();
                info.fsize = root[i]["fsize"].asInt64();
                info.atime = root[i]["atime"].asInt64();
                info.mtime = root[i]["mtime"].asInt64();
                info.pack_path = root[i]["pack_path"].asString();
                info.real_path = root[i]["real_path"].asString();
                info.url = root[i]["url"].asString();
                Insert(info);
            }
            return true;
        }
    };
}

#endif
//gdb找错误：先run，再bt查看函数作用栈